var Guid = function () {
    var guid = '';
    for (var i = 1; i <= 32; i++) {
        var n = Math.floor(Math.random() * 16.0).toString(16);
        guid += n;
        if ((i == 8) || (i == 12) || (i == 16) || (i == 20))
            guid += '-';
    }
    return guid;
};

var interface = function (data, parent) {
    this.config = data;
    this.parent = parent;
    this.level = 0;
    this.parentIdArray = [];
};

interface.prototype = {
    constructor: this,
    render: function () {
        this.icon = $('<i class="' + this.config.contentType + '">' + this.config.contentType + '</i>');
        this.title = $('<div class="title"></div>');
        this.name = $('<div class="name"></div>');
        this.index = $('<span class="index">' + this.config.contentIndex + '</span>');
        this.text = $('<span class="text">' + this.config.title + '</span>');
        this.name.append(this.index).append(this.text);
        this.icon.addClass(this.closeIconClass);
        this.title.append(this.icon);
        this.title.append(this.name);
        this.html = $('<div class="interface"></div>');
        this.html.append(this.title);
        this.title.click(() => {
            this.parent.active(this.config.id);
        });
        this.title.mousedown((e) => {
            if (3 == e.which) {
                this.parent.active(this.config.id);
                this.parent.event.shallMenu(e, false, this);
            };
        });
        return this.html;
    },
    unActive: function () {
        this.title.removeClass('active');
    },
    active: function () {
        this.title.addClass('active');
        this.parent.event.active(this);
    },
    parentLevel: function () {
        if (this.config.parentId === undefined) {
            this.name.css('left', '5px');
            return;
        };
        var checkLevel = (items, parentId) => {
            if (parentId && items.hasOwnProperty(parentId)) {
                this.parentIdArray.push(parentId);
                this.level++;
                checkLevel(items, items[parentId].config.parentId);
            };
        };
        checkLevel(this.parent.items, this.config.parentId);
        this.title.css('padding-left', 10 + (this.level * 10) + 'px');
        this.name.css('left', 35 + (this.level * 10) + 'px');
    },
    delete: function () {
        this.parent.event.delete(this.config);
    },
    move: function () {
        this.parent.event.move(this.config, this.parent.__FolderArray);
    }
}

var folderEX = function (data, parent) {
    this.isFolder = true;
    this.config = data;
    this.parent = parent;
    this.status = this.config.parentId === undefined;
    this.closeIconClass = 'fa-folder-o';
    this.openIconClass = 'fa-folder-open-o';
    this.folder = [];
    this.interface = [];

    this.icon = $('<i class="fa"></i>');
    this.title = $('<div class="title"></div>');
    this.name = $('<div class="name"></div>');
    this.index = $('<span class="index">' + this.config.contentIndex + '</span>');
    this.text = $('<span class="text">' + this.config.title + '</span>');
    this.name.append(this.index).append(this.text);
    this.scrollBox = $('<div></div>');

    this.icon.addClass(this.closeIconClass);
    this.title.append(this.icon);
    this.title.append(this.name);
    // this.title.append(this.renameEle);

    this.folderList = $('<div clas="list" style="display:' + (this.status ? 'block' : 'none') + '"></div>');
    this.interfaceList = $('<div class="list" style="display:' + (this.status ? 'block' : 'none') + '"></div>');
    this.html = $('<div class="folder"></div>');
    this.html.append(this.title);
    this.html.append(this.scrollBox);
    this.scrollBox.append(this.folderList);
    this.scrollBox.append(this.interfaceList);

    this.title.click(() => {
        if (this.config.parentId !== undefined) {
            if (this.status) {
                this.close();
            } else {
                this.open();
            }
            this.parent.active(this.config.id);
        };
    });
    this.title.mousedown((e) => {
        if (3 == e.which) {
            this.parent.active(this.config.id);
            this.parent.event.shallMenu(e, true, this);
        };
    });
};

folderEX.prototype = {
    constructor: this,
    render: function () {
        return this.html;
    },
    unActive: function () {
        this.title.removeClass('active');
    },
    active: function () {
        this.title.addClass('active');
    },
    open: function () {
        this.status = true;
        this.folderList.css('display', 'block');
        this.interfaceList.css('display', 'block');
        this.icon.removeClass(this.closeIconClass).addClass(this.openIconClass);
    },
    close: function () {
        this.status = false;
        this.folderList.css('display', 'none');
        this.interfaceList.css('display', 'none');
        this.icon.removeClass(this.openIconClass).addClass(this.closeIconClass);
    },
    append: function (obj) {
        if (obj.config.contentType == 'folder') {
            this.folder.push(obj);
        } else {
            this.interface.push(obj);
        };
    },
    sort: function () {
        this.folder = this.folder.sort((a, b) => {
            return a.config.contentIndex - b.config.contentIndex
        });

        for (let i = 0; i < this.folder.length; i++) {
            const element = this.folder[i];
            this.folderList.append(element.render());
        };

        this.interface = this.interface.sort((a, b) => {
            return a.config.contentIndex - b.config.contentIndex
        });

        for (let i = 0; i < this.interface.length; i++) {
            const element = this.interface[i];
            this.interfaceList.append(element.render());
        };
    },
    parentLevel: function () {
        this.level = 0;
        this.parentIdArray = [];
        if (this.config.parentId === undefined) {
            this.name.css('left', '5px');
            return;
        };
        var checkLevel = (items, parentId) => {
            if (parentId && items.hasOwnProperty(parentId)) {
                this.level++;
                this.parentIdArray.push(parentId);
                checkLevel(items, items[parentId].config.parentId);
            };
        };
        checkLevel(this.parent.items, this.config.parentId);
        this.title.css('padding-left', 10 + (this.level * 10) + 'px');
        this.name.css('left', 30 + (this.level * 10) + 'px');
    },
    disable: function () {
        this.html.remove();
    },
    showEditor: function (cb) {
        this.renameEle = $('<div class="title rename active"></div>');
        this.renameIcon = $('<i class="fa"></i>');
        if (this.status) {
            this.renameIcon.addClass(this.openIconClass);
        } else {
            this.renameIcon.addClass(this.closeIconClass);
        };
        this.renameName = $('<div class="name"></div>');
        this.renameEleIndex = $('<span class="index">' + this.config.contentIndex + '</span>');
        this.renameEleText = $('<span class="text"></span>');
        this.renameEleInput = $('<input type="text">');
        this.renameEleInput.val(this.config.title);
        this.renameEleText.append(this.renameEleInput);
        this.renameName.append(this.renameEleIndex).append(this.renameEleText);
        this.renameEle.append(this.renameIcon).append(this.renameName);

        this.renameEle.css('padding-left', 10 + (this.level * 10) + 'px');
        this.renameName.css('left', 30 + (this.level * 10) + 'px');

        this.title.before(this.renameEle);
        this.renameEleIndex.mousewheel((event) => {
            var text = parseInt(this.renameEleIndex.text());
            if (event.deltaY > 0) {
                var _text = text - 1;
                if (_text) {
                    this.renameEleIndex.text(parseInt(_text));
                } else {
                    this.renameEleIndex.text(1)
                };
            } else if (event.deltaY < 0) {
                var _text = text + 1;
                if (_text > 99) {
                    this.renameEleIndex.text(99)
                } else {
                    this.renameEleIndex.text(parseInt(_text));
                };
            };
        });
        this.renameEleInput.focus();
        this.renameEleInput.blur(() => {
            var _value = this.renameEleInput.val();
            var _index = parseInt(this.renameEleIndex.text());
            cb({
                contentIndex: _index,
                title: _value
            });
            this.renameEle.remove();
            this.parent.hideMark();
        });
        this.renameEleInput.keydown((e) => {
            if (e.keyCode == 13) {
                this.renameEleInput.blur();
            }
        });
        this.parent.showMark();
    },
    rename: function () {
        this.showEditor((data) => {
            if (data.title != this.config.title || data.contentIndex != this.config.contentIndex) {
                this.parent.event.rename(this.config, data);
            };
        });
    },
    newFolder: function () {
        var _Folder = new folderEX({
            contentIndex: 1,
            contentType: "folder",
            id: null,
            parentId: this.config.id,
            title: "",
        }, this.parent);
        if (!this.status) {
            this.open();
        };
        _Folder.parentLevel();
        this.folderList.prepend(_Folder.render());
        _Folder.showEditor((data) => {
            if (data.title != _Folder.config.title || data.contentIndex != _Folder.config.contentIndex) {
                this.parent.event.newFolder(_Folder.config, data);
            };
            _Folder.disable();
        });
    },
    delete: function () {
        this.parent.event.delete(this.config);
    },
    move: function () {
        this.parent.event.move(this.config, this.parent.__FolderArray);
    },
    clear: function () {
        this.scrollBox.empty();
    },
};
var listEX = function () {
    this.data = [];
    this.html = $('<div id="list" class="list"><div class="root"></div></div>');
    this.mark = $('<div class="mark" style="display:none"></div>');
    this.html.append(this.mark);
    this.items = {};
    this.event = {
        refresh: function (e) { },
        active: function (e) { },
        shallMenu: function (e) { },
        rename: function (e) { },
        newFolder: function (e) { },
        delete: function (e) { },
        move: function (e) { },
        export: function () { },
    };
    this.activeObj = null;
    // this.setData(data);
};

listEX.prototype = {
    constructor: this,
    render: function () {
        return this.html;
    },
    on: function (str, event) {
        if (this.event.hasOwnProperty(str)) {
            this.event[str] = event;
        };
    },
    setWidth: function (num) {
        this.html.css('width', num + 'px');
    },
    show: function () {
        this.html.css('display', 'block');
    },
    hide: function () {
        this.html.css('display', 'none');
    },
    each: function (cb) {
        for (const key in this.items) {
            if (this.items.hasOwnProperty(key)) {
                const element = this.items[key];
                cb(element);
            }
        }
    },
    setData: function (_array) {
        var data = this.getCache();
        this.clear();
        this.__FolderArray = [];

        for (let i = 0; i < _array.length; i++) {
            const element = _array[i];
            if (element.contentType == 'folder') {
                this.items[element.id] = new folderEX(element, this);
                this.__FolderArray.push(element);
            } else {
                this.items[element.id] = new interface(element, this);
            }
        };
        this.each((element) => {
            if (element.config.parentId !== undefined) {
                this.items[element.config.parentId].append(element);
            };
        });
        this.each((element) => {
            if (element.config.contentType == 'folder') {
                element.sort();
            };
        });

        this.each((element) => {
            element.parentLevel();
        });

        this.setCache(data);
    },
    active: function (id) {
        if (id === null) {
            return
        };
        if (this.items.hasOwnProperty(id)) {
            if (this.items[id] !== this.activeObj) {
                this.unActive();
                this.items[id].active();
                this.activeObj = this.items[id];
                for (let i = 0; i < this.activeObj.parentIdArray.length; i++) {
                    const parentId = this.activeObj.parentIdArray[i];
                    if (parentId) {
                        this.items[parentId].open();
                    };
                }
            };
            this.activeMove();
        } else {
            this.unActive();
            this.activeObj = null;
        };
    },
    activeMove: function () {
        if (this.activeObj) {
            var top = this.activeObj.html.offset().top;
            var height = this.root.scrollBox.height();

            console.log(top, height);
            if (top < 24) {
                this.root.scrollBox.scrollTop(this.root.scrollBox.scrollTop() - 100);
                setTimeout(() => {
                    this.activeMove();
                }, 5);
            } else if (top > height + 10) {
                this.root.scrollBox.scrollTop(this.root.scrollBox.scrollTop() + 100);
                setTimeout(() => {
                    this.activeMove();
                }, 5);
            }


            // var Min = this.html.offset().left;
            // var Max = Min + this.html.width();
            // var left = this.activeObj.html.offset().left;
            // var width = this.activeObj.html.outerWidth(true);
            // if (left + 6 < Min) {
            //     this.html.scrollLeft(this.html.scrollLeft() - 20);
            //     setTimeout(() => {
            //         this.activeMove();
            //     }, 5);
            // } else if (left > Max - width) {
            //     this.html.scrollLeft(this.html.scrollLeft() + 20);
            //     setTimeout(() => {
            //         this.activeMove();
            //     }, 5);
            // }
        };
    },
    unActive: function () {
        this.each((ele) => {
            ele.unActive();
        });
        this.activeObj = null;
    },
    refresh: function (cb) {
        this.event.refresh(this, cb);
    },
    clear: function () {
        if (this.root) {
            this.root.disable();
        };
        this.items = {};
        this.root = new folderEX({
            id: null,
            contentType: 'folder',
            title: '/ 根目录',
            contentIndex: ''
        }, this);
        this.items[null] = this.root;
        this.html.find('.root').append(this.root.render());
        this.root.icon.css('display', 'none');
        this.root.name.css({
            'left': '0px'
        });
        this.root.text.css({
            'left': '0px',
            'font-size': '12px',
            'height': '35px',
            'line-height': '35px'
        });
        this.closeAllButton = $('<div class="closeAllButton fa fa-minus-square-o" title="全部收起"></div>');
        this.closeAllButton.click(() => {
            this.unActive();
            this.each((element) => {
                if (element instanceof folderEX && element.status && element !== this.root) {
                    if (element.status) {
                        element.close();
                    };
                };
            });
        });
        this.refreshButton = $('<div class="refreshButton fa fa-refresh" title="刷新"></div>');
        this.refreshButton.click(() => {
            this.refresh();
        });
        this.newFolderButton = $('<div class="newFolderButton fa fa-file-text" title="新建文件夹"></div>');
        this.newFolderButton.click(() => {
            this.root.newFolder();
        });
        this.exportButton = $('<div class="export fa fa-file-excel-o" title="导出Excel"></div>');
        this.exportButton.click(() => {
            this.event.export();
        });
        this.root.scrollBox.addClass('custom-scroll').addClass('theme-scroll').css({
            'top': '35px',
            'left': '0',
            'bottom': '0',
            'right': '0',
            'overflow-x': 'hidden',
            'overflow-y': 'auto',
            'position': 'absolute'
        });
        this.root.html.css({
            width: '100%',
            height: '100%'
        });
        this.root.name.append(this.closeAllButton);
        this.root.name.append(this.refreshButton);
        this.root.name.append(this.newFolderButton);
        this.root.name.append(this.exportButton);
        this.root.title.off('mousedown').css({
            'background': '#dddddd',
            'height': '33px',
            'line-height': '33px',
            'cursor': 'default',
        });
    },
    showMark: function () {
        this.mark.css('display', 'block');
        this.root.scrollBox.css('overflow', 'hidden');

    },
    hideMark: function () {
        this.mark.css('display', 'none');
        this.root.scrollBox.css({
            'overflow-x': 'hidden',
            'overflow-y': 'auto',
        });
    },
    getCache: function () {
        var cacheArray = [];
        var cacheActiveObject = null;
        if (this.activeObj) {
            cacheActiveObject = this.activeObj.config.id;
        };
        this.each((element) => {
            if (element.config.contentType == 'folder' && element.status) {
                cacheArray.push(element.config.id);
            };
        });
        return {
            "listArray": cacheArray,
            "listActiveObjId": cacheActiveObject,
        }
    },
    setCache: function (data) {
        if (this.items.hasOwnProperty(data.listActiveObjId)) {
            this.active(data.listActiveObjId);
        };
        for (let i = 0; i < data.listArray.length; i++) {
            const itemId = data.listArray[i];
            if (this.items.hasOwnProperty(itemId) && (this.items[itemId].config.contentType == 'folder')) {
                this.items[itemId].open();
            }
        };

    }
}

module.exports.list = function () {
    return new listEX();
};
module.exports.folder = folderEX;
module.exports.interface = interface;
